package com.client.config;

import com.client.Initialize;
import com.client.entity.B_client;
import com.client.entity.PassAuthor;
import com.client.mapper.MessageDao;
import com.client.mapper.PassAuthorDao;
import com.client.service.KeyService;
import com.client.service.MessageService;
import com.client.service.MigrationService;
import com.client.service.Sm9Service;
import com.client.utils.AESutil;
import com.client.utils.MessageUtils;
import com.client.utils.Utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.Filter;
import org.springframework.integration.annotation.Router;
import org.springframework.integration.annotation.Transformer;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.ip.udp.UnicastReceivingChannelAdapter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.messaging.handler.annotation.Payload;

import java.sql.Timestamp;
import java.util.*;

/*
 *   接收并处理UDP请求
 *
 */
@Slf4j
@Configuration
public class DataReceiveConfigration {
    @Autowired
    MessageDao messageDao;
    @Autowired
    Sm9Service userService;
    @Autowired
    PassAuthorDao passAuthorDao;
    @Autowired
    MessageService messageService;
    @Autowired
    MigrationService migrationService;
    @Autowired
    KeyService keyService;
    @Value("${udp.receive}")
    private Integer port;

    @Bean
    public MessageChannel orderChannel() {
        return new QueueChannel();
    }

    @Bean
    public UnicastReceivingChannelAdapter getUnicastReceivingChannelAdapter() {
        UnicastReceivingChannelAdapter adapter = new UnicastReceivingChannelAdapter(port);//实例化一个udp 端口
        adapter.setOutputChannelName("udp");
        return adapter;
    }

    @Transformer(inputChannel = "udp", outputChannel = "udpString")
    public Map<String, Object> transformer(@Payload byte[] s, @Headers Map<String, Object> headers) {
        Map<String, Object> map = null;
        Map<String, Object> X = new HashMap<>();    //transformer如果返回为空会报错，所以用这个填充一下，在过滤器那里会被丢弃
        try {
            //认证1 || 密钥交换 || 正常通信
            map = Utils.getObjectMapFromByte(s);
            return map;
        } catch (Exception e) {
            //认证2345--需要先进行SM9解密
            if (Initialize.HPS) {
                //如果可以计算迁移
                migrationService.Decrypt(s);
                return X;
            } else {
                //不能进行计算迁移
                byte[] bytes;
                try {
                    bytes = userService.Decrypt(s);
                    map = Utils.getObjectMapFromByte(bytes);
                    return map;
                } catch (Exception e1) {
                    log.info("sm9解密失败");
                    return X;
                }
            }
        }
    }

    //对数据包进行过滤--检验完整性、避免重放攻击
    @Filter(inputChannel = "udpString", outputChannel = "retransform")
    public boolean filter(Map<String, Object> map) {
        if (map.isEmpty())
            return false;
        if (map.containsKey("type")) {
            if (map.get("type").equals("CERTIFICATION_ONE")
                    || map.get("type").equals("CERTIFICATION_TWO")
                    || map.get("type").equals("CERTIFICATION_THREE")
                    || map.get("type").equals("CERTIFICATION_FOUR")
                    || map.get("type").equals("CERTIFICATION_FIVE")
            ) {  //认证数据包
                return verifyCertification(map);
            } else {//密钥交换数据包
                if (!map.containsKey("id")) {
                    log.info("缺少参数");
                    return false;
                }
                B_client client = messageService.getClient((String) map.get("id"));
                if (client == null)
                    return false;
                return verifyExchange(map, client.getMy_n());
            }
        } else if (map.containsKey("body")) { //正常通信数据包
            if (!map.containsKey("id")) {
                log.info("缺少参数");
                return false;
            }
            PassAuthor client = passAuthorDao.queryByName((String) map.get("id"));
            if (client == null) {
                log.info("[" + map.get("id") + "]尚未完成认证和密钥交换");
                return false;
            }
            return verifyFormal(map, client.getK());
        }
        return false;
    }

    //对body进行AES解密
    @Transformer(inputChannel = "retransform", outputChannel = "udpFilter")
    public Map<String, Object> transformer2(Map<String, Object> map, @Headers Map<String, Object> headers) {
        if (map.containsKey("body")) {
            PassAuthor client = passAuthorDao.queryByName((String) map.get("id"));
            //AES解密
            byte[] data = new byte[0];
                data = AESutil.decrypt((byte[]) map.get("body"), client.getK());
            Map<String, Object> result = null;
            try {
                result = Utils.getObjectMapFromByte(data);
            } catch (Exception e) {
                log.info("Map反序列化失败");
            }
            result.put("b_id", map.get("id"));
            result.put("b_time", map.get("time"));
            result.put("b_uuid", map.get("uuid"));
            result.put("b_uid",map.get("uid")); //body外的uid

            //停止重发
            MessageService.deleteMessage(map.get("uid").toString());
            messageDao.add(map.get("id").toString(), keyService.getId(), headers.get("ip_address").toString(), (Integer)headers.get("ip_port"), ((UUID) map.get("uid")).toString(),
                    ((UUID) map.get("uuid")).toString(), 0, result.get("type").toString(), new Timestamp(MessageUtils.getNowTime().getTime()));
            return result;

        } else {
            return map;
        }
    }

    //对解密迁移的结果进行过滤
    @Filter(inputChannel = "decrypt-result", outputChannel = "udpFilter")
    public boolean filter1(Map<String, Object> map) {
        return verifyCertification(map);
    }

    @Router(inputChannel = "udpFilter")
    public String routing(Map<String, Object> map) {
        if (map.get("type").equals("CERTIFICATION_ONE")) {
            return "certification1";
        } else if (map.get("type").equals("CERTIFICATION_TWO")) {
            return "certification2";
        } else if (map.get("type").equals("CERTIFICATION_THREE")) {
            return "certification3";
        } else if (map.get("type").equals("CERTIFICATION_FOUR")) {
            return "certification4";
        } else if (map.get("type").equals("CERTIFICATION_FIVE")) {
            return "certification5";
        } else if (map.get("type").equals("EXCHANGE_ONE")) {
            return "exchange1";
        } else if (map.get("type").equals("EXCHANGE_TWO")) {
            return "exchange2";
        } else if (map.get("type").equals("EXCHANGE_THREE")) {
            return "exchange3";
        } else if (map.get("type").equals("EXCHANGE_FOUR")) {
            return "exchange4";
        } else if (map.get("type").equals("MIGRATION_ENCRYPT_RESULT")) {
            return "Encrypt-result";
        } else if (map.get("type").equals("MIGRATION_DECRYPT_RESULT")) {
            return "Decrypt-result";
        } else if (map.get("type").equals("MIGRATION_SIGN_RESULT")) {
            return "Sign-result";
        } else if (map.get("type").equals("MIGRATION_VERIFY_RESULT")) {
            return "Verify-result";
        } else if (map.get("type").equals("MIGRATION_EXCHANGE_ONE_RESULT")) {
            return "Exchange1-result";
        } else if (map.get("type").equals("MIGRATION_EXCHANGE_TWO_RESULT")) {
            return "Exchange2-result";
        } else if (map.get("type").equals("DEVICE_AUTHORITY_MANAGER")) {
            return "Device-Rights-Management";
        }else if (map.get("type").equals("CONFIRM_GET_PACKET")) {
            return "CONFIRM_GET_PACKET";
        }
        return null;
    }

    //认证数据包的检验
    public boolean verifyCertification(Map<String, Object> map) {
        if (map.isEmpty() || !map.containsKey("time") || !map.containsKey("uuid")
                || !map.containsKey("id") || !map.containsKey("type") || !map.containsKey("hash")) {
            log.info("数据包缺少参数");
            return false;
        } else {

            //时间差，uuid，Hash
            Date time = (Date) map.get("time");
            Date nowTime = MessageUtils.getNowTime();
            messageDao.delete();   //删除30s之前的UUID
            if (nowTime.getTime() - time.getTime() > 30 * 1000) {
                log.info("数据包超时");
                return false;
            } else if (messageDao.query(map.get("uuid").toString()) != null) {
                log.info("数据包重复");
                return false;
            } else if (!Arrays.equals((byte[]) map.get("hash"), MessageUtils.HashOfCertification(map))) {
                log.info("HASH校验错误");
                return false;
            }
            return true;
        }
    }

    //密钥交换数据包的检验
    public boolean verifyExchange(Map<String, Object> map, int n) {
        if (map.isEmpty() || !map.containsKey("time") || !map.containsKey("uuid")
                || !map.containsKey("id") || !map.containsKey("type") || !map.containsKey("hash")) {
            log.info("数据包缺少参数");
            return false;
        } else {

            //时间差，uuid，Hash
            Date time = (Date) map.get("time");
            Date nowTime = MessageUtils.getNowTime();
            messageDao.delete();   //删除30s之前的UUID
            if (nowTime.getTime() - time.getTime() > 30 * 1000) {
                log.info("数据包超时");
                return false;
            } else if (messageDao.query(((UUID) map.get("uuid")).toString()) != null) {
                log.info("数据包重复");
                return false;
            } else if (!Arrays.equals((byte[]) map.get("hash"), MessageUtils.HashOfExchange(map, n))) {
                log.info("HASH校验错误");
                return false;
            }
            return true;
        }
    }

    //正常通信数据包的检验
    public boolean verifyFormal(Map<String, Object> map, byte[] k) {
        if (map.isEmpty() || !map.containsKey("time") || !map.containsKey("uuid")
                || !map.containsKey("id") || !map.containsKey("body") || !map.containsKey("hash")) {
            log.info("数据包缺少参数");
            return false;
        } else {
            //时间差，uuid，Hash
            Date time = (Date) map.get("time");
            Date nowTime = MessageUtils.getNowTime();
            messageDao.delete();   //删除30s之前的UUID
            if (nowTime.getTime() - time.getTime() > 30 * 1000) {
                log.info("数据包超时");
                return false;
            } else if (messageDao.query(((UUID) map.get("uuid")).toString()) != null) {
                log.info("数据包重复");
                return false;
            } else if (!Arrays.equals((byte[]) map.get("hash"), MessageUtils.HashOfFormal(map, k))) {
                log.info("HASH校验错误");
                return false;
            }
            return true;
        }
    }

}
